/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstdio>
#include <cstdlib>
#include <string>
#include <string.h>
#include "cashdevice_napi.h"
#include "js_native_api.h"
#include "js_native_api_types.h"
#include "napi/native_common.h"
#include "napi/native_api.h"
#include "makecard_def.h"
#include "makecard_srv_client.h"
#include "hilog_wrapper.h"
#include "makecard_utils.h"

using namespace SwanLink::Finance;

thread_local static MakecardSrvClient& g_makecardClient = MakecardSrvClient::GetInstance();

/**
 * @brief 定义接口函数
 * static napi_value XXXX(napi_env env, napi_callback_info info)
 * @param env
 * @param info
 * @return napi_value
 */
static napi_value SetConfig(napi_env env, napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void* priv_data = nullptr;
    size_t argc = 3;
    napi_value args[3] = { 0 };
    struct tTmpStruct {
        int handle;
        int configType;
        int configValue;
        int ret;
    };

    tTmpStruct* pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env, argc >= 3, "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->configType));
    NAPI_CALL(env, napi_get_value_int32(env, args[2], &pVar->configValue));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void* data)->napi_status {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        int& handle = pVar->handle;
        int& configType = pVar->configType;
        int& configValue = pVar->configValue;
        int& ret = pVar->ret;

        ret = g_makecardClient.SetConfig(handle, configType, configValue);

        return napi_ok;
    };
    async_result_work result_func = [](napi_env env, void* data)->napi_value {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [](napi_env env, void* data) {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        delete pVar;
    };
    AsyncCallback* async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return AsyncPromise(env, "SetConfig", async);
}
static napi_value SetStandbyParam(napi_env env, napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void* priv_data = nullptr;
    size_t argc = 4;
    napi_value args[4] = { 0 };
    struct tTmpStruct {
        int handle;
        int dir;
        int pos;
        int standbyTime;
        int ret;
    };

    tTmpStruct* pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env, argc >= 4, "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->dir));
    NAPI_CALL(env, napi_get_value_int32(env, args[2], &pVar->pos));
    NAPI_CALL(env, napi_get_value_int32(env, args[3], &pVar->standbyTime));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void* data)->napi_status {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        int& handle = pVar->handle;
        int& dir = pVar->dir;
        int& pos = pVar->pos;
        int& standbyTime = pVar->standbyTime;
        int& ret = pVar->ret;

        ret = g_makecardClient.SetStandbyParam(handle, dir, pos, standbyTime);

        return napi_ok;
    };
    async_result_work result_func = [](napi_env env, void* data)->napi_value {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [](napi_env env, void* data) {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        delete pVar;
    };
    AsyncCallback* async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return AsyncPromise(env, "SetStandbyParam", async);
}
static napi_value PrintCard(napi_env env, napi_callback_info info)
{
    MAKECARD_HILOGD(MAKECARD_JS_NAPI, "PrintCard enter");
    napi_value this_arg = nullptr;
    void* priv_data = nullptr;
    size_t argc = 2;
    napi_value args[2] = { 0 };
    struct tTmpStruct {
        int handle;
        BmpInfo cardBmpInfo;
        int ret;
    };

    tTmpStruct* pVar = new tTmpStruct();
    napi_value direction;
    napi_value lpFrontBGR;
    napi_value lpFrontK;
    napi_value lpFrontO;
    napi_value lpBackBGR;
    napi_value lpBackK;
    napi_value lpBackO;
    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env, argc >= 2, "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_named_property(env, args[1], "xor", &direction));
    NAPI_CALL(env, napi_get_named_property(env, args[1], "lpFrontBGR", &lpFrontBGR));
    NAPI_CALL(env, napi_get_named_property(env, args[1], "lpFrontK", &lpFrontK));
    NAPI_CALL(env, napi_get_named_property(env, args[1], "lpFrontO", &lpFrontO));
    NAPI_CALL(env, napi_get_named_property(env, args[1], "lpBackBGR", &lpBackBGR));
    NAPI_CALL(env, napi_get_named_property(env, args[1], "lpBackK", &lpBackK));
    NAPI_CALL(env, napi_get_named_property(env, args[1], "lpBackO", &lpBackO));
    size_t resultStrLen = 0;
    NAPI_CALL(env, napi_get_value_uint32(env, direction, &pVar->cardBmpInfo.direction));
    napi_get_value_string_utf8(env, lpFrontBGR, pVar->cardBmpInfo.lpFrontBGR, 512, &resultStrLen);
    NAPI_CALL(env, napi_get_value_string_utf8(env, lpFrontK, pVar->cardBmpInfo.lpFrontK, 512, &resultStrLen));
    NAPI_CALL(env, napi_get_value_string_utf8(env, lpFrontO, pVar->cardBmpInfo.lpFrontO, 512, &resultStrLen));
    NAPI_CALL(env, napi_get_value_string_utf8(env, lpBackBGR, pVar->cardBmpInfo.lpBackBGR, 512, &resultStrLen));
    NAPI_CALL(env, napi_get_value_string_utf8(env, lpBackK, pVar->cardBmpInfo.lpBackK, 512, &resultStrLen));
    NAPI_CALL(env, napi_get_value_string_utf8(env, lpBackO, pVar->cardBmpInfo.lpBackO, 512, &resultStrLen));
    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void* data)->napi_status {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        int& handle = pVar->handle;
        BmpInfo& cardBmpInfo = pVar->cardBmpInfo;
        int& ret = pVar->ret;
        MAKECARD_HILOGD(MAKECARD_JS_NAPI, "PrintCard enter9");
        MAKECARD_HILOGD(MAKECARD_JS_NAPI, "PrintCard bmpinfo is %d", cardBmpInfo.direction);
        ret = g_makecardClient.PrintCard(handle, cardBmpInfo);
        MAKECARD_HILOGD(MAKECARD_JS_NAPI, "PrintCard enter10");
        return napi_ok;
    };
    async_result_work result_func = [](napi_env env, void* data)->napi_value {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        napi_value result;
        MAKECARD_HILOGD(MAKECARD_JS_NAPI, "PrintCard enter11");
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));
        MAKECARD_HILOGD(MAKECARD_JS_NAPI, "PrintCard enter12");
        return result;
    };
    async_free_work free_func = [](napi_env env, void* data) {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        MAKECARD_HILOGD(MAKECARD_JS_NAPI, "PrintCard enter13");
        delete pVar;
        MAKECARD_HILOGD(MAKECARD_JS_NAPI, "PrintCard enter14");
    };
    AsyncCallback* async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    MAKECARD_HILOGD(MAKECARD_JS_NAPI, "PrintCard out");
    return AsyncPromise(env, "PrintCard", async);
}
static napi_value GetDeviceInfo(napi_env env, napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void* priv_data = nullptr;
    size_t argc = 2;
    napi_value args[2] = { 0 };
    struct tTmpStruct {
        int handle;
        int infoType;
        int ret;
        char infoValue[256];
    };

    tTmpStruct* pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env, argc >= 2, "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->infoType));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void* data)->napi_status {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        int& handle = pVar->handle;
        int& infoType = pVar->infoType;
        int& ret = pVar->ret;
        ret = g_makecardClient.GetDeviceInfo(handle, infoType, pVar->infoValue);

        return napi_ok;
    };
    async_result_work result_func = [](napi_env env, void* data)->napi_value {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        napi_value resultInfoValue;
        napi_value resultRet;
        napi_value result;
        NAPI_CALL(env, napi_create_string_utf8(env, pVar->infoValue, NAPI_AUTO_LENGTH, &resultInfoValue));
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &resultRet));
        NAPI_CALL(env, napi_create_object(env, &result));
        NAPI_CALL(env, napi_set_named_property(env, result, "ret", resultRet));
        NAPI_CALL(env, napi_set_named_property(env, result, "infoValue", resultInfoValue));
        return result;
    };
    async_free_work free_func = [](napi_env env, void* data) {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        delete pVar;
    };
    AsyncCallback* async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return AsyncPromise(env, "GetDeviceInfo", async);
}
static napi_value GetErrorString(napi_env env, napi_callback_info info)
{
    MAKECARD_HILOGD(MAKECARD_JS_NAPI, "GetErrorString enter");
    napi_value this_arg = nullptr;
    void* priv_data = nullptr;
    size_t argc = 2;
    napi_value args[2] = { 0 };
    struct tTmpStruct {
        int handle;
        int status;
        int ret;
        char statusDesc[256];
    };

    tTmpStruct* pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env, argc >= 2, "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->status));
    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void* data)->napi_status {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        int& handle = pVar->handle;
        int& status = pVar->status;
        char* statusDesc = pVar->statusDesc;
        pVar->ret = g_makecardClient.GetErrorString(handle, status, statusDesc);
        MAKECARD_HILOGD(MAKECARD_JS_NAPI, "GetErrorString workfunc out,status was %{public}s", statusDesc);
        return napi_ok;
    };
    async_result_work result_func = [](napi_env env, void* data)->napi_value {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        napi_value resultStatusDesc;
        napi_value result;
        napi_value resultRet;
        NAPI_CALL(env, napi_create_string_utf8(env, pVar->statusDesc, NAPI_AUTO_LENGTH, &resultStatusDesc));
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &resultRet));
        NAPI_CALL(env, napi_create_object(env, &result));
        NAPI_CALL(env, napi_set_named_property(env, result, "ret", resultRet));
        NAPI_CALL(env, napi_set_named_property(env, result, "statusDesc", resultStatusDesc));
        return result;
    };
    async_free_work free_func = [](napi_env env, void* data) {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        delete pVar;
    };
    AsyncCallback* async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    MAKECARD_HILOGD(MAKECARD_JS_NAPI, "GetErrorString out");
    return AsyncPromise(env, "GetErrorString", async);
}
static napi_value MoveCard(napi_env env, napi_callback_info info)
{
    MAKECARD_HILOGD(MAKECARD_JS_NAPI, "move card enter");
    napi_value this_arg = nullptr;
    void* priv_data = nullptr;
    size_t argc = 2;
    napi_value args[2] = { 0 };
    struct tTmpStruct {
        int handle;
        int postionMoveTo;
        int ret;
    };

    tTmpStruct* pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env, argc >= 2, "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->postionMoveTo));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void* data)->napi_status {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        int& handle = pVar->handle;
        int& postionMoveTo = pVar->postionMoveTo;
        int& ret = pVar->ret;
        MAKECARD_HILOGD(MAKECARD_JS_NAPI, "move card work_func enter,postion was %{public}d", postionMoveTo);
        ret = g_makecardClient.MoveCard(handle, postionMoveTo);

        return napi_ok;
    };
    async_result_work result_func = [](napi_env env, void* data)->napi_value {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [](napi_env env, void* data) {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        delete pVar;
    };
    AsyncCallback* async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    MAKECARD_HILOGD(MAKECARD_JS_NAPI, "move card out");
    return AsyncPromise(env, "MoveCard", async);
}
static napi_value FlipCard(napi_env env, napi_callback_info info)
{
    MAKECARD_HILOGD(MAKECARD_JS_NAPI, "flip card enter");
    napi_value this_arg = nullptr;
    void* priv_data = nullptr;
    size_t argc = 1;
    napi_value args[1] = { 0 };
    struct tTmpStruct {
        int handle;
        int ret;
    };

    tTmpStruct* pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void* data)->napi_status {
        MAKECARD_HILOGD(MAKECARD_JS_NAPI, "flip card workfunc enter");
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        int& handle = pVar->handle;
        int& ret = pVar->ret;

        ret = g_makecardClient.FlipCard(handle);

        return napi_ok;
    };
    async_result_work result_func = [](napi_env env, void* data)->napi_value {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [](napi_env env, void* data) {
        tTmpStruct* pVar = static_cast<tTmpStruct*>(data);
        delete pVar;
    };
    AsyncCallback* async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    MAKECARD_HILOGD(MAKECARD_JS_NAPI, "flip card out");
    return AsyncPromise(env, "FlipCard", async);
}

EXTERN_C_START
/*
 * function for module exports
 */
    static napi_value MakecardInit(napi_env env, napi_value exports)
{
    MAKECARD_HILOGD(MAKECARD_JS_NAPI, "Enter");
    Common::ClientInit(&g_makecardClient, env, exports);
    napi_property_descriptor desc[] = {
    DECLARE_NAPI_FUNCTION("GetSupportAccess", Common::GetSupportAccess),
    DECLARE_NAPI_FUNCTION("Open", Common::Open),
    DECLARE_NAPI_FUNCTION("Close", Common::Close),
    DECLARE_NAPI_FUNCTION("QueryStatus", Common::QueryStatus),
    DECLARE_NAPI_FUNCTION("Reset", Common::Reset),
    DECLARE_NAPI_FUNCTION("SetConfig", SetConfig),
    DECLARE_NAPI_FUNCTION("SetStandbyParam", SetStandbyParam),
    DECLARE_NAPI_FUNCTION("PrintCard", PrintCard),
    DECLARE_NAPI_FUNCTION("GetDeviceInfo", GetDeviceInfo),
    DECLARE_NAPI_FUNCTION("GetErrorString", GetErrorString),
    DECLARE_NAPI_FUNCTION("MoveCard", MoveCard),
    DECLARE_NAPI_FUNCTION("FlipCard", FlipCard),
    DECLARE_CONST_VAR(ERR_CARD_JAM),
    DECLARE_CONST_VAR(ERR_REJECT_BOX_OPEN),
    DECLARE_CONST_VAR(ERR_REJECT_BOX_FULL),
    DECLARE_CONST_VAR(ERR_RIBBON_ERROR),
    DECLARE_CONST_VAR(ERR_NO_CARD),
    DECLARE_CONST_VAR(ERR_FLIPPER_ERROR),
    DECLARE_CONST_VAR(ERR_CARD_FEED_ERROR),
    DECLARE_CONST_VAR(ERR_COVER_OPEN),
    DECLARE_CONST_VAR(ERR_REQUEST_NOT_SUPPORTED),
    DECLARE_CONST_VAR(ERR_THE_FIRMWARE_COMMAND_NOT_SUPPORTED),
    DECLARE_CONST_VAR(ERR_OPEN_SPECIFIED_DEVICE_OR_FILE_FAILED),
    DECLARE_CONST_VAR(ERR_FLIPPER_NOT_ATTACHED),
    DECLARE_CONST_VAR(ERR_RIBBON_MISSING),
    DECLARE_CONST_VAR(ERR_CARD_EJECT_ERROR),
    DECLARE_CONST_VAR(ERR_CARD_OUT),
    DECLARE_CONST_VAR(ERR_FILM_OUT),
    DECLARE_CONST_VAR(ERR_FILM_ERROR),
    DECLARE_CONST_VAR(ERR_FILM_MISSING),
    DECLARE_CONST_VAR(ERR_RIBBON_OUT),
    DECLARE_CONST_VAR(ERR_MAGNETIC_ENCODING_MODULE_NOT_ATTACHED)
    };
    napi_value obj;
    napi_create_object(env, &obj);
    NAPI_CALL(env, napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc));
    napi_set_named_property(env, exports, "makecard", obj);
    MAKECARD_HILOGD(MAKECARD_JS_NAPI, "Success");

    return exports;
}
EXTERN_C_END

/*
 * Module definition
 */
    static napi_module g_module = {
        .nm_version = 1,
        .nm_flags = 0,
        .nm_filename = "makecard",
        .nm_register_func = MakecardInit,
        .nm_modname = "makecard",
        .nm_priv = nullptr,
        .reserved = {0}
};

/*
 * Module registration
 */
extern "C" __attribute__((constructor)) void RegisterModule(void)
{
    napi_module_register(&g_module);
}
